//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
#include "NotifyWindowList.h"
#include <winuser.h>

NotifyWindowList::NotifyWindowList(): m_pNotifyList(NULL)
{
}

// Reset the list.
// Returns 0 if successfull or error code if failed for any node.
DWORD NotifyWindowList::ResetRecordList()
{
    NOTIFY_NODE* pNext = NULL;
    DWORD error = 0;

    while (m_pNotifyList) {
        pNext = m_pNotifyList->pNext;
        if (NULL != LocalFree((HLOCAL)m_pNotifyList)) {
            ASSERT(0);                   
            error = GetLastError();
            DEBUGMSG( TRUE, (TEXT("Error: ResetList Failed with Error=%d"), error));
        }
        m_pNotifyList = pNext;
    }

    m_pNotifyList = NULL;
    return error;
}

// Add an event node to the list.
// Returns NULL if failed. Call GetLastError to get error code.
// Returns Pointer to the node if successful
NOTIFY_NODE* NotifyWindowList::AddWindow(DEVNOTIFY_EVENT spkEv)
{   
    NOTIFY_NODE* pNode = NULL;
    pNode = (NOTIFY_NODE*)LocalAlloc(LPTR, sizeof (NOTIFY_NODE));
    if (!pNode) {
        return NULL;
    }
    // Add the information to the node.
    pNode->spkEv.hWndNotify = spkEv.hWndNotify;
    pNode->spkEv.Msg = spkEv.Msg;

    // Add the node to the head of list.
    pNode->pNext = m_pNotifyList;
    m_pNotifyList = pNode;

    return pNode;
}

// Returns TRUE if successful, FALSE if failed.
BOOL NotifyWindowList::RemoveWindow(HWND hWnd)
{
    NOTIFY_NODE* pNode = m_pNotifyList;
    NOTIFY_NODE* pPrevNode = NULL;
    BOOL bFound = FALSE;

    // Verify it is a valid wnd handle or it's not an empty list.
    if (!hWnd || !m_pNotifyList) {
        return FALSE;
    }

    while (pNode) {
        // Check if this node is the one we are looking for.
        if (pNode->spkEv.hWndNotify == hWnd) {
            // Check if this is the first node in the list.
            if (pNode == m_pNotifyList) {
                m_pNotifyList = pNode->pNext;
            } else {
                pPrevNode->pNext = pNode->pNext;
            }
            // Now free the node.
            LocalFree((HLOCAL)pNode);
            bFound = TRUE;
            break;
        }
        // No move to the next node now, keeping a link
        pPrevNode = pNode;
        pNode = pNode->pNext;
    }
   return bFound;
}

// Returns TRUE if successful, FALSE if message sending to one/more window failed.
BOOL NotifyWindowList::SendMessage(DWORD dwVal)
{    
    NOTIFY_NODE *pNode = m_pNotifyList;
    BOOL success = TRUE;

    // Iterate through all the windows and send the message with val specified.
    while (pNode) {
        success &= PostMessage(pNode->spkEv.hWndNotify, pNode->spkEv.Msg, (WPARAM)dwVal, (LPARAM)NULL);
        pNode = pNode->pNext;
    }
    return success;
}

BOOL NotifyWindowList::SendMessage(NOTIFY_NODE* pNode, DWORD dwVal)
{
    if (!pNode) {
        return FALSE;
    }
    return PostMessage(pNode->spkEv.hWndNotify, pNode->spkEv.Msg, (WPARAM)dwVal, (LPARAM)NULL);
}